package org.paul.library.manager;

import android.support.annotation.NonNull;
import android.util.Log;
import org.paul.library.base.BaseBean;

import java.util.Map;
import java.util.concurrent.*;

public class ThreadManager {

    private final String TAG = getClass().getSimpleName();

    private NetManager netManager = NetManager.getInstance();

    private static class Holder {
        private static ThreadManager instance = new ThreadManager();
    }

    private ThreadManager() {
        int cpuNum = Runtime.getRuntime().availableProcessors();
        fixedThreadPool = Executors.newFixedThreadPool(cpuNum + 1);
    }

    public static ThreadManager getInstance() {
        return Holder.instance;
    }

    private ExecutorService fixedThreadPool;

    public interface HandleRet<T> {

        void handleRet(T t);

        default boolean cancel() {
            return false;
        }

        default HandleRet bindTask(FutureTask futureTask) {
            return this;
        }
    }

    public abstract static class HandleRetImpl<T> implements HandleRet<T> {

        private FutureTask futureTask;

        @Override
        public boolean cancel() {
            if (null != futureTask) {
                return futureTask.cancel(true);
            }
            return false;
        }

        @Override
        public HandleRet bindTask(FutureTask futureTask) {
            this.futureTask = futureTask;
            return this;
        }
    }

    class BaseTask<T> extends FutureTask<T> {

        private HandleRet handleRet;
        private String tag;

        public BaseTask(@NonNull Callable<T> callable) {
            super(callable);
        }

        public BaseTask(@NonNull Runnable runnable, T result) {
            super(runnable, result);
        }

        BaseTask(@NonNull Callable<T> callable, HandleRet handleRet) {
            super(callable);
            this.handleRet = handleRet;
            this.handleRet.bindTask(this);
        }

        BaseTask(@NonNull Callable<T> callable, HandleRet handleRet, String tag) {
            this(callable, handleRet);
            this.tag = tag;
        }

        @Override
        protected void done() {
            super.done();
            T t = null;
            try {
                t = get();
            } catch (CancellationException e) {
//                e.printStackTrace();
                Log.e(TAG, String.format("Task[%1$s] canceled", tag));
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            } finally {
                handleRet.handleRet(t);
            }
        }
    }

    public <T extends BaseBean> void submitPost(final String spec, final Map<String, Object> params, final Class<T> clz,
                                                final HandleRet<T> handleRet) {

        BaseTask<T> futureTask = new BaseTask<T>(new Callable<T>() {
            @Override
            public T call() throws Exception {
                return netManager.post(spec, params, clz);
            }
        }, handleRet, spec);
        fixedThreadPool.submit(futureTask);
    }

    public void submit(Runnable runnable) {
        fixedThreadPool.submit(runnable);
    }

    public <T extends BaseBean> void submitGet(final String spec, final Class<T> clz,
                                               final HandleRet<T> handleRet) {

        BaseTask<T> futureTask = new BaseTask<T>(new Callable<T>() {
            @Override
            public T call() throws Exception {
                return netManager.get(spec, clz);
            }
        }, handleRet);
        fixedThreadPool.submit(futureTask);
    }
}
